import * as THREE from 'three';
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';

var delta;

var vs = [];
var fs = [];
var mesh = [];
var tex = [];
var mat = [];

var texture_loader = new THREE.TextureLoader();

const clock = new THREE.Clock();

class Smoke {
  constructor(viewer) {
    this.viewer = viewer;
    this.init();
    this.addText();
  }

  init() {
    var camera = this.viewer.camera;

    tex['smoke'] = texture_loader.load(require('@/assets/images/common/smoke.png'));

    tex['fire'] = texture_loader.load(require('@/assets/images/common/fire.png'));

    vs['sprite'] = `
      
      
      attribute vec3 offset;
      attribute vec2 scale;
      attribute vec4 quaternion;
      attribute float rotation;
      attribute vec4 color;
      attribute float blend;
      attribute float texture;
      uniform float time;
      varying vec2 vUv;
      varying vec4 vColor;
      varying float vBlend;
      varying float num;
      vec3 localUpVector=vec3(0.0,1.0,0.0);
      
      
      void main(){
      
      
      float angle=time*rotation;
      vec3 vRotated=vec3(position.x*scale.x*cos(angle)-position.y*scale.y*sin(angle),position.y*scale.y*cos(angle)+position.x*scale.x*sin(angle),position.z);
      
      
      vUv=uv;
      vColor=color;
      vBlend=blend;
      num=texture;
      
      
      vec3 vPosition;
      
      
      
      
      /*
      vec3 vLook=normalize(offset-cameraPosition);
      vec3 vRight=normalize(cross(vLook,localUpVector));
      vec3 vUp=normalize(cross(vLook,vRight));
      vPosition=vRight*vRotated.x+vUp*vRotated.y+vLook*vRotated.z;
      */
      
      
      vec3 vLook=offset-cameraPosition;
      vec3 vRight=normalize(cross(vLook,localUpVector));
      vPosition=vRotated.x*vRight+vRotated.y*localUpVector+vRotated.z;
      
      
      
      gl_Position=projectionMatrix*modelViewMatrix*vec4(vPosition+offset,1.0);
      
      
      }
      
      
      `;

    fs['sprite'] = `
      
      
      const int count=3;
      uniform sampler2D map[count];
      varying vec2 vUv;
      varying vec4 vColor;
      varying float vBlend;
      varying float num;
      
      
      void main(){
      
      
      if(num==0.0){ gl_FragColor=texture2D(map[0],vUv)*vColor; }
      else if(num==1.0){ gl_FragColor=texture2D(map[1],vUv)*vColor; }
      else if(num==2.0){ gl_FragColor=texture2D(map[2],vUv)*vColor; }
      
      
      gl_FragColor.rgb*=gl_FragColor.a;
      gl_FragColor.a*=vBlend;
      
      
      }
      
      
      `;

    var particles = [];

    // ____________________ GRASS ____________________

    var particles_grass_a = [];

    particles_grass_a.push({
      offset: [10, 2, 0],
      scale: [4, 4],
      quaternion: [0, 0, 0, 4],
      rotation: 0,
      color: [1, 1, 1, 1],
      blend: 1,
      texture: 2,
    });

    for (var n = 0; n < 100; n++) {
      var scale = Math.random() * 0.5 + 0.5;
      particles_grass_a.push({
        offset: [Math.random() * 20 - 10, scale / 2, Math.random() * 20 - 10],
        scale: [scale, scale],
        quaternion: [0, 0, 0, 4],
        rotation: 0,
        color: [1, 1, 1, 1],
        blend: 1,
        texture: 2,
      });
    }

    // ____________________ SMOKE ____________________

    var wind_x = 0.002;
    var wind_y = 0;
    var wind_z = 0;

    var particles_smoke_a = [];

    var particles_emmiter = [];

    particles_emmiter.push({
      position: { x: 25.0, y: -5, z: 1.33 },
      radius_1: 0.5,
      radius_2: 2,
      radius_height: 5,
      add_time: 0.1,
      elapsed: 0,
      live_time_from: 4,
      live_time_to: 4.5,
      opacity_decrease: 0.004,
      rotation_from: 2,
      rotation_to: 3,
      speed_from: 0.005,
      speed_to: 0.01,
      scale_from: 0.1,
      scale_increase: 0.003,
      color_from: [1, 1, 1],
      color_to: [1, 1, 1],
      color_speed_from: 1,
      color_speed_to: 1,
      brightness_from: 1.0,
      brightness_to: 1,
      opacity: 0.4,
      blend: 0.5,
      texture: 0,
    });

    // ____________________ PARTICLES EMMITER EMMIT ____________________

    function particles_emmiter_emmit(item) {
      var radius_1 = item.radius_1 * Math.sqrt(Math.random());
      var theta = 2 * Math.PI * Math.random();
      var x_1 = item.position.x + radius_1 * Math.cos(theta);
      var z_1 = item.position.z + radius_1 * Math.sin(theta);

      var radius_2 = item.radius_2 * Math.sqrt(Math.random());
      var theta = 2 * Math.PI * Math.random();
      var x_2 = x_1 + radius_2 * Math.cos(theta);
      var z_2 = z_1 + radius_2 * Math.sin(theta);

      let direction_x = x_2 - x_1;
      let direction_y = item.radius_height;
      let direction_z = z_2 - z_1;

      var speed = Math.random() * (item.speed_to - item.speed_from) + item.speed_from;

      var divide =
        (1 /
          Math.sqrt(
            direction_x * direction_x + direction_y * direction_y + direction_z * direction_z,
          )) *
        speed;
      direction_x *= divide;
      direction_y *= divide;
      direction_z *= divide;

      var brightness =
        Math.random() * (item.brightness_to - item.brightness_from) + item.brightness_from;

      particles_smoke_a.push({
        offset: [x_1, item.position.y, z_1],
        scale: [item.scale_from, item.scale_from],
        quaternion: [direction_x, direction_y, direction_z, 3],
        rotation: Math.random() * (item.rotation_to - item.rotation_from) + item.rotation_from,
        color: [1, 1, 1, item.opacity],
        blend: item.blend,
        texture: item.texture,
        live: Math.random() * (item.live_time_to - item.live_time_from) + item.live_time_from,
        scale_increase: item.scale_increase,
        opacity_decrease: item.opacity_decrease,
        color_from: [
          item.color_from[0] * brightness,
          item.color_from[1] * brightness,
          item.color_from[2] * brightness,
        ],
        color_to: [
          item.color_to[0] * brightness,
          item.color_to[1] * brightness,
          item.color_to[2] * brightness,
        ],
        color_speed:
          Math.random() * (item.color_speed_to - item.color_speed_from) + item.color_speed_from,
        color_pr: 0,
      });
    }

    // ____________________ PERTICLES EMMITER UPDATE ____________________

    function particles_emmiter_update() {
      var max = particles_emmiter.length;

      for (var n = 0; n < max; n++) {
        var item = particles_emmiter[n];

        var add = 0;

        item.elapsed += delta;
        add = Math.floor(item.elapsed / item.add_time);
        item.elapsed -= add * item.add_time;
        if (add > (0.016 / item.add_time) * 60 * 1) {
          item.elapsed = 0;
          add = 0;
        }

        while (add--) {
          particles_emmiter_emmit(item);
        }
      }

      var max = particles_smoke_a.length;
      var alive = new Array(max);
      var i = 0;

      for (var j = 0; j < max; j++) {
        var item = particles_smoke_a[j];

        if (item.color_pr < 1) {
          var color_r =
            item.color_from[0] + (item.color_to[0] - item.color_from[0]) * item.color_pr;
          var color_g =
            item.color_from[1] + (item.color_to[0] - item.color_from[1]) * item.color_pr;
          var color_b =
            item.color_from[1] + (item.color_to[0] - item.color_from[2]) * item.color_pr;
          item.color_pr += delta * item.color_speed;
          item.color[0] = color_r;
          item.color[1] = color_g;
          item.color[2] = color_b;
        } else {
          item.color[0] = item.color_to[0];
          item.color[1] = item.color_to[1];
          item.color[2] = item.color_to[2];
        }

        item.offset[0] += item.quaternion[0] + wind_x;
        item.offset[1] += item.quaternion[1] + wind_y;
        item.offset[2] += item.quaternion[2] + wind_z;
        item.scale[0] += item.scale_increase;
        item.scale[1] += item.scale_increase;

        if (item.live > 0) {
          item.live -= delta;
        } else {
          item.color[3] -= item.opacity_decrease;
        }
        if (item.color[3] > 0) {
          alive[i] = item;
          i++;
        }
      }

      alive.length = i;
      particles_smoke_a = alive;
    }

    // ____________________ PARTICLES UPDATE ____________________

    function particles_update() {
      particles_emmiter_update();

      particles = [];

      var max_1 = particles_smoke_a.length;
      particles.length = max_1;
      for (var n = 0; n < max_1; n++) {
        particles[n] = particles_smoke_a[n];
      }

      var max_2 = max_1 + particles_grass_a.length;
      particles.length = max_2;
      var i = 0;
      for (var n = max_1; n < max_2; n++) {
        particles[n] = particles_grass_a[i];
        i++;
      }

      var count = particles.length;
      var item = camera.position;
      var x = item.x;
      var y = item.y;
      var z = item.z;

      for (var n = 0; n < count; n++) {
        var item = particles[n].offset;
        particles[n].d = Math.sqrt(
          Math.pow(x - item[0], 2) + Math.pow(y - item[1], 2) + Math.pow(z - item[2], 2),
        );
      }

      particles.sort((a, b) => b.d - a.d);

      var offset = new Float32Array(count * 3);
      var scale = new Float32Array(count * 2);
      var quaternion = new Float32Array(count * 4);
      var rotation = new Float32Array(count);
      var color = new Float32Array(count * 4);
      var blend = new Float32Array(count);
      var texture = new Float32Array(count);

      for (var n = 0; n < count; n++) {
        // 1 VALUE
        var item = particles[n];
        rotation[n] = item.rotation;
        texture[n] = item.texture;
        blend[n] = item.blend;

        // 2 VALUE
        var p = n * 2;
        var one = p + 1;
        var i_scale = item.scale;
        scale[p] = i_scale[0];
        scale[one] = i_scale[1];

        // 3 VALUE
        var p = n * 3;
        var one = p + 1;
        var two = p + 2;
        var i_offset = item.offset;
        offset[p] = i_offset[0];
        offset[one] = i_offset[1];
        offset[two] = i_offset[2];

        // 4 VALUE
        var p = n * 4;
        var one = p + 1;
        var two = p + 2;
        var three = p + 3;
        var i_color = item.color;
        color[p] = i_color[0];
        color[one] = i_color[1];
        color[two] = i_color[2];
        color[three] = i_color[3];
        var i_quaternion = item.quaternion;
        quaternion[p] = i_quaternion[0];
        quaternion[one] = i_quaternion[1];
        quaternion[two] = i_quaternion[2];
        quaternion[three] = i_quaternion[3];
      }

      var item = mesh['sprite'].geometry.attributes;
      item.offset = new THREE.InstancedBufferAttribute(offset, 3).setUsage(THREE.DynamicDrawUsage);
      item.scale = new THREE.InstancedBufferAttribute(scale, 2).setUsage(THREE.DynamicDrawUsage);
      item.quaternion = new THREE.InstancedBufferAttribute(quaternion, 4).setUsage(
        THREE.DynamicDrawUsage,
      );
      item.rotation = new THREE.InstancedBufferAttribute(rotation, 1).setUsage(
        THREE.DynamicDrawUsage,
      );
      item.color = new THREE.InstancedBufferAttribute(color, 4).setUsage(THREE.DynamicDrawUsage);
      item.blend = new THREE.InstancedBufferAttribute(blend, 1).setUsage(THREE.DynamicDrawUsage);
      item.texture = new THREE.InstancedBufferAttribute(texture, 1).setUsage(
        THREE.DynamicDrawUsage,
      );

      mesh['sprite'].geometry._maxInstanceCount = count;
    }

    var geometry = new THREE.InstancedBufferGeometry();
    geometry.setAttribute(
      'position',
      new THREE.Float32BufferAttribute(
        new Float32Array([
          -0.5, 0.5, 0, -0.5, -0.5, 0, 0.5, 0.5, 0, 0.5, -0.5, 0, 0.5, 0.5, 0, -0.5, -0.5, 0,
        ]),
        3,
      ),
    );
    geometry.setAttribute(
      'uv',
      new THREE.Float32BufferAttribute(new Float32Array([0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0]), 2),
    );
    geometry.setAttribute('offset', new THREE.InstancedBufferAttribute(new Float32Array(), 3));
    geometry.setAttribute('scale', new THREE.InstancedBufferAttribute(new Float32Array(), 2));
    geometry.setAttribute('quaternion', new THREE.InstancedBufferAttribute(new Float32Array(), 4));
    geometry.setAttribute('rotation', new THREE.InstancedBufferAttribute(new Float32Array(), 1));
    geometry.setAttribute('color', new THREE.InstancedBufferAttribute(new Float32Array(), 4));
    geometry.setAttribute('blend', new THREE.InstancedBufferAttribute(new Float32Array(), 1));
    geometry.setAttribute('texture', new THREE.InstancedBufferAttribute(new Float32Array(), 1));

    mat['sprite'] = new THREE.ShaderMaterial({
      uniforms: {
        map: { value: [tex['smoke'], tex['fire'], tex['grass']] },
        time: { value: 0 },
      },
      vertexShader: vs['sprite'],
      fragmentShader: fs['sprite'],
      side: THREE.DoubleSide,
      transparent: true,
      //   depthWrite: true,
      depthTest: false,
      blending: THREE.CustomBlending,
      blendEquation: THREE.AddEquation,
      blendSrc: THREE.OneFactor,
      blendDst: THREE.OneMinusSrcAlphaFactor,
    });

    mesh['sprite'] = new THREE.Mesh(geometry, mat['sprite']);
    mesh['sprite'].frustumCulled = false;
    mesh['sprite'].matrixAutoUpdate = false;
    mesh['sprite'].updateMatrixWorld = function () {};
    // this.viewer.scene.add(mesh['sprite']);

    const group = this.viewer.scene.children.find((item) => item.name === 'panoramaGroup');
    group.add(mesh['sprite']);

    this.addAnimation(() => {
      delta = clock.getDelta();
      particles_update();
      mat['sprite'].uniforms.time.value = clock.elapsedTime;
    });
  }

  addText() {
    const objectConfigs = [
      {
        position: { x: 25, y: -4, z: 1.33 },
        color: '#FF6347',
        text: 'CO2',
      }, // 红色文本
      {
        position: { x: 25, y: -3.5, z: 1.33 },
        color: '#32CD32',
        text: 'O2',
      }, // 绿色文本
      {
        position: { x: 25, y: -3, z: 1.33 },
        color: '#1E90FF',
        text: 'N2',
      }, // 蓝色文本
      {
        position: { x: 25, y: -2.5, z: 1.33 },
        color: '#FFD700',
        text: 'CH4',
      }, // 黄色文本
    ];
    // for (var i = 0; i < 100; i++) {
    //   const obj = { position: { x: 25, y: Math.random(), z: 1.33 }, color: '#FF6347', text: 'CO2' };
    //   objectConfigs.push();
    // }

    // 用于存储多个对象
    let objects = [];

    // 创建多个文本对象并添加到场景中
    objectConfigs.forEach((config, index) => {
      const textElement = document.createElement('div');
      textElement.style.position = 'absolute';
      textElement.style.fontSize = '20px'; // 设置字体大小
      textElement.style.color = config.color; // 设置文本颜色
      textElement.style.fontFamily = 'Arial, sans-serif'; // 设置字体
      textElement.innerHTML = config.text; // 设置文本内容

      // 创建CSS3D对象
      let object = new CSS3DObject(textElement);
      object.scale.set(0.03, 0.03, 0.03);

      // 设置每个对象的初始位置
      object.position.set(config.position.x, config.position.y, config.position.z);
      object.rotation.y = -(90 / 180) * Math.PI;

      // 添加到特定的组
      const group = this.viewer.scene.children.find((item) => item.name === 'panoramaGroup');
      group.add(object);

      // 将对象加入数组，存储初始位置
      objects.push({
        object: object,
        initialPosition: { ...config.position }, // 保存初始位置
        startTime: performance.now(),
        lifetime: 2, // 持续时间（秒）
      });
    });

    // 添加动画
    this.addAnimation(() => {
      const currentTime = performance.now();

      // 遍历所有对象并更新位置和透明度
      objects.forEach((objData) => {
        const { object, initialPosition, startTime, lifetime } = objData;
        let elapsedTime = (currentTime - startTime) / 1000;

        if (object) {
          // 向上移动
          object.position.y += 0.01;
          // 逐渐减少透明度
          object.element.style.opacity = 1 - elapsedTime / lifetime;

          // 如果动画持续时间到，重置对象
          if (elapsedTime >= lifetime) {
            // 重置对象的状态
            const group = this.viewer.scene.children.find((item) => item.name === 'panoramaGroup');
            group.remove(object);

            // 重新设置对象的初始状态
            object.position.set(initialPosition.x, initialPosition.y, initialPosition.z); // 重置为初始位置
            object.element.style.opacity = 1; // 重置透明度
            objData.startTime = performance.now(); // 重置开始时间
            group.add(object); // 将对象重新添加到场景中
          }
        }
      });
    });
  }

  remove() {
    this.viewer.removeAnimate(this.animaObject);
  }

  addAnimation(animation) {
    this.animaObject = {
      fun: animation,
      content: this,
    };
    this.viewer.addAnimate(this.animaObject);
  }
}
export { Smoke };
